﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using NetMicro.EventBus.Messages;

namespace NetMicro.EventBus.Internal
{
    public class EventHandlerInvoker : IEventHandlerInvoker
    {
        public EventHandlerInvoker(
            IMessageSerializer messageSerializer,
            IServiceScopeFactory serviceScopeFactory)
        {
            MessageSerializer = messageSerializer;
            ServiceScopeFactory = serviceScopeFactory;
        }

        private IServiceScopeFactory ServiceScopeFactory { get; }
        private IMessageSerializer MessageSerializer { get; }

        public async Task InvokeAsync(MessageTransfer messageTransfer,
            EventHandlerDescriptor eventHandlerDescriptor)
        {
            using var scope = ServiceScopeFactory.CreateScope();
            var eventHandlerInstance =
                scope.ServiceProvider.GetRequiredService(eventHandlerDescriptor.EventHandlerType);
            if (messageTransfer.MsgBody is null)
                throw new InvalidCastException($"[EventBus] event body content is null, msgId: {messageTransfer.MsgId}");
            var eventBody =
                MessageSerializer.Deserialize(messageTransfer.MsgBody, eventHandlerDescriptor.EventType);
            if (eventBody is null)
                throw new InvalidCastException($"[EventBus] event body content deserialize to null, msgId: {messageTransfer.MsgId}");

            var method =
                eventHandlerDescriptor.EventHandlerType.GetMethod("Execute",
                    new Type[] { eventHandlerDescriptor.EventType, typeof(IDictionary<string, string>) });

            var task = (Task)method!.Invoke(eventHandlerInstance, new object[] { eventBody, messageTransfer.Items });
            await task.ConfigureAwait(false);
        }
    }
}